"""
生成器:一种特殊的迭代器类
其内部也定义了__iter__ 和 __next__方法
普通迭代器在使用该容器迭代一组数据时，必须事先将所有数据存储到容器中，才能开始迭代；
而生成器却不同，它可以实现在迭代的同时生成元素。
"""
class Foo:
    def __init__(self):
        print("__init__")

    def __iter__(self):
        print("__iter__ 1")
        yield 1
        print("__iter__ 2")
        yield 2


def generate_func(n):
    """
    函数的返回值用的是 yield 关键字，而不是 return 关键字，此类函数又成为生成器函数。
    和 return 相比，yield 除了可以返回相应的值，还有一个更重要的功能
        即每当程序执行完该语句时，程序就会暂停执行。
        不仅如此，即便调用生成器函数，Python 解释器也不会执行函数中的代码，它只会返回一个生成器（对象）。

    要想使生成器函数得以执行，或者想使执行完 yield 语句立即暂停的程序得以继续执行，有以下 2 种方式：
        1.通过生成器（上面程序中的 num）调用 next() 内置函数或者 __next__() 方法；
        2.通过 for 循环遍历生成器。
    :param n:
    :return:
    """
    print("even running begin")
    for i in range(0, n + 1, 2):
        yield "num" + str(i)
        print("even running continue")

    print("even running end")


if __name__ == "__main__":
    g1 = Foo()
    print(type(g1))
    from collections.abc import Iterator
    from collections.abc import Iterable

    print(isinstance(g1, Iterator))
    print(isinstance(g1, Iterable))
    for g in g1:
        print(g)

    print("=========================")
    g2 = generate_func(10)  # 这里并不会立即执行generate_func的代码，而只会返回一个生成器对象
    print(type(g2))
    print(g2.__next__())  # 调用 next() 内置函数或者 __next__() 方法才会开始执行函数体里面的代码
    print("*************")
    for g in g2:
        print(g)
